local luaExtend = require "LuaExtend.lua"
local filter=require("packages.filter")
local FZutil={}

local function setAllTextOutLine(node)
    if node then
        local nodes=node:getChildren()
        local type_=tolua.type(node)
        local name=node:getName()
        if (type_ == "ccui.Text" or type_ == "cc.Label")
            and (string.sub(name,-2)~="_N") then
            node:enableOutline(cc.c4b(0,0,0,255),2)
            if type_ == "ccui.Text" then
            	node:getVirtualRenderer():setAdditionalKerning(-4)
            else    
                node:setAdditionalKerning(-4)
            end
        end
        for _, sub in ipairs(nodes) do
            setAllTextOutLine(sub)
        end
    end
end

local vsize=cc.Director:getInstance():getVisibleSize()


function FZutil.unicode_to_utf8(convertStr)
    if type(convertStr)~="string" then
        return convertStr
    end
    local resultStr=""
    
    if convertStr == nil or tonumber(string.len(convertStr)) <= 0 then
        return resultStr
    end
    
    local i=1
    while true do
        local num1=string.byte(convertStr,i)
        local unicode
        if num1~=nil and string.sub(convertStr,i,i+1)=="\\u" then
            unicode=tonumber("0x"..string.sub(convertStr,i+2,i+5))
            i=i+6
        elseif num1~=nil then
            unicode=num1
            i=i+1
        else
            break
        end
       -- print(unicode)
        if unicode <= 0x007f then
            resultStr=resultStr..string.char(bit.band(unicode,0x7f))
        elseif unicode >= 0x0080 and unicode <= 0x07ff then
            resultStr=resultStr..string.char(bit.bor(0xc0,bit.band(bit.rshift(unicode,6),0x1f)))
            resultStr=resultStr..string.char(bit.bor(0x80,bit.band(unicode,0x3f)))
        elseif unicode >= 0x0800 and unicode <= 0xffff then
            resultStr=resultStr..string.char(bit.bor(0xe0,bit.band(bit.rshift(unicode,12),0x0f)))
            resultStr=resultStr..string.char(bit.bor(0x80,bit.band(bit.rshift(unicode,6),0x3f)))
            resultStr=resultStr..string.char(bit.bor(0x80,bit.band(unicode,0x3f)))
        end
    end
    resultStr=resultStr..'\0'
    --print(resultStr)
    return resultStr
end

---读取cocos导出的lua文件，并设置布局，把节点里所有的文本加描边
--用于读取scene
--@param nodeName string cocos导出的lua文件的名字（不要".lua"）
--@return #table 节点容器，根节点为["root"]。。。注意，返回对象本身不是node
function FZutil.createSceneNode(nodeName)
--    local nd=cc.CSLoader:createNode(nodeName..".csb")
--    nd:setContentSize(vsize)
--    ccui.Helper:doLayout(nd)
--    setAllTextOutLine(nd)
--    local ret={root=nd}
--    setmetatable(ret, luaExtend)
--    return ret
---
    local nd=require(nodeName).create()
    nd.root:setContentSize(vsize)
    ccui.Helper:doLayout(nd.root)
    setAllTextOutLine(nd.root)
    if nd.animation then
    	nd.root.animation=nd.animation
    end
    return nd
end

function FZutil.createCellNode(nodeName)
--    local nd=cc.CSLoader:createNode(nodeName..".csb")
--    setAllTextOutLine(nd)
--    local ret={root=nd}
--    setmetatable(ret, luaExtend)
--    FZutil.changeRootNodeToWidget(ret)
--    return ret
---
    local nd=require(nodeName).create()
    setAllTextOutLine(nd.root)
    FZutil.changeRootNodeToWidget(nd)
    if nd.animation then
        nd.root.animation=nd.animation
    end
    return nd
end

--创建一个不自动描边的节点(也不会自动布局)
function FZutil.createNoneOutLineNode( nodeName )
    local nd=require(nodeName).create()
    if nd.animation then
        nd.root.animation=nd.animation
    end
    return nd
end

---把一个cellmap里面的Root转化ccui.Widget类型
--@param cellmap table 含有node为Root的uimap
function FZutil.changeRootNodeToWidget(cellmap)
    local new_root=FZutil.changeNodeToWidget(cellmap.root)
    cellmap.root=new_root
end

---把cc.Node转化成ccui.Widget
--@param node cc.Node 要转化的节点
--@return #ccui.Widget 转化后的Widget
function FZutil.changeNodeToWidget(node)
	local parent=node:getParent()
	local children=node:getChildren()
	local widget=ccui.Widget:create()
    for _, ch in pairs(children) do
        FZutil.changeParent(ch,widget)
    end
    if parent then
    	parent:addChild(widget)
    	node:removeSelf()
    end
    return widget
end

function FZutil.createMap(rootnode)
    local ret={root=rootnode}
    setmetatable(ret, luaExtend)
    return ret
end

function FZutil.changeParent(ch,new_parent)
    ch:retain()
    ch:removeSelf()
    new_parent:addChild(ch)
    ch:release()
end

---把组件树里的所有文件都设置描边
-- @param node cc.node ui组件树的根
FZutil.setAllTextOutLine=setAllTextOutLine

---创建一个可以不会穿透点击事件的Layer
--@return #ccui.Layout 一个于屏幕等大的ccui.Layout,并且可以响应点击
function FZutil.createUILayer()
    local lay=ccui.Layout:create()
    lay:setTouchEnabled(true)
    lay:setContentSize(display.width,display.height)
    lay:setBackGroundColor(cc.c3b(0,0,0))
    lay:setBackGroundColorOpacity(math.floor(0.7*0xff))
    lay:setBackGroundColorType(ccui.LayoutBackGroundColorType.solid)
    return lay
end

---创建一个可以不会穿透点击事件的Layer
--@return #ccui.Layout 一个于屏幕等大的ccui.Layout,并且可以响应点击
function FZutil.createTransportUILayer()
    local lay=ccui.Layout:create()
    lay:setTouchEnabled(true)
    lay:setSwallowTouches(false)
    lay:setContentSize(display.width,display.height)
    lay:setBackGroundColor(cc.c3b(0,0,0))
    lay:setBackGroundColorOpacity(math.floor(0.7*0xff))
    lay:setBackGroundColorType(ccui.LayoutBackGroundColorType.none)
    return lay
end

---窗口打开特效
--@param eff_node cc.Node 执行特效的节点
function FZutil.windowShowEff(eff_node)
    FZutil.disableTouch()
    eff_node:setScale(0)
    transition.scaleTo(eff_node,{scale=1,time=0.3,easing="BACKOUT",onComplete=function()
        FZutil.enableTouch()
    end})
end

---窗口关闭特效（特效结束后移除节点）
--@param eff_node cc.Node 执行特效的节点
--@param remove_node cc.Node 移除的节点
--@param onComplete function 动作完成时的回调方法，可以为nil
function FZutil.windowEffCloseToRemove(eff_node,remove_node,onComplete)
    FZutil.disableTouch()
    local parama={scale=0,time=0.3,easing="BACKIN"}
	parama.onComplete=function()
	   FZutil.enableTouch()
	    if remove_node then
            remove_node:removeSelf()
        end
        if onComplete then
        	onComplete()
        end
    end
    transition.scaleTo(eff_node,parama)
end

---释放缓存
function FZutil.clearCache()
    if FzFixCocosBug then 
        FzFixCocosBug.clearArmatureCache()
    end
    if device.platform=="windows" then
        cc.SpriteFrameCache:getInstance():removeUnusedSpriteFrames()
        cc.Director:getInstance():getTextureCache():removeUnusedTextures()
        cc.FileUtils:getInstance():purgeCachedEntries()
    else
        cc.Director:getInstance():purgeCachedData()
    end
end

---检查点是否在矩形里面
--@param p cc.point(x,y)
--@param box cc.rect(x,y,width,height)
--@return #boolean 是否
function FZutil.checkAABB(p,box)
    if p.x<box.x or p.x>box.x+box.width or p.y<box.y or p.y > box.y+box.height then
        return false
    end
    return true
end

--检查是否touch是否位于按钮上<br>
--touch:cc.Touch<br>
--btn:按钮node
function FZutil.checkBtnHit(touch,btn)
    local box=btn:getBoundingBox()
    local p=btn:getParent():convertTouchToNodeSpace(touch)
    return FZutil.checkAABB(p,box)
end

local callCount = 0

function FZutil.disableTouch()
    callCount = callCount + 1
    if callCount == 1 then
	   cc.Director:getInstance():getEventDispatcher():setEnabled(false)
	end
    print("disable touch",callCount)
end

function FZutil.enableTouch()
    callCount = callCount - 1
    if callCount == 0 then
        cc.Director:getInstance():getEventDispatcher():setEnabled(true)
    end
    print("enable touch",callCount)
end

function FZutil.printHex(buf) --@return string
    local len=string.len(buf)
    local ret=""
    for i=1,len do
        local char_code=string.byte(buf,i,i+1)
        local temp=string.format("%02X",char_code)
        ret=ret..temp
    end
    return ret
end

function FZutil.HexToString(buf)
    local len=string.len(buf)
    local ret=""
    for i=1,len,2 do
        local byte=tonumber(string.sub(buf,i,i+1),16)
        ret=ret..string.char(byte)
    end
    return ret
end

function FZutil.printCallStack(startLevel,maxLevel)
    local startLevel = startLevel or 3 --0表示getinfo本身,1表示调用getinfo的函数(printCallStack),2表示调用printCallStack的函数,可以想象一个getinfo(0级)在顶的栈.
    local maxLevel = maxLevel or 10 --最大递归10层
    local ret="\n"

    for level = startLevel, maxLevel do
        -- 打印堆栈每一层
        local info = debug.getinfo( level, "nSl") 
        if info == nil then break end
        ret=ret .. string.format('[string "%s"]:%d: function: %s\n',info.source or "",info.currentline,info.name or "")

        -- 打印该层的参数与局部变量
        local index = 1 --1表示第一个参数或局部变量, 依次类推
        while true do
            local name, value = debug.getlocal( level, index )
            if name == nil then break end

            local valueType = type( value )
            local valueStr
            if valueType == 'string' then
                -- valueStr = FZutil.printHex(value)
                valueStr=value
            elseif valueType == "number" then
                valueStr = string.format("%.2f", value)
            else 
                valueStr = tostring(value)
            end
            ret=ret .. string.format( "\t%s = %s\n", name, valueStr ) 
            index = index + 1
        end
    end
    print(ret)
    return  ret
end

local function pauseAll(node)
    node:pause()
    local children=node:getChildren()
    for _, child in pairs(children) do
        pauseAll(child)
    end
end
FZutil.pauseAll=pauseAll

local function resumeAll(node)
    node:resume()
    local children=node:getChildren()
    for _, child in pairs(children) do
        resumeAll(child)
    end
end
FZutil.resumeAll=resumeAll

---
--发送日志
--@param err string 错误消息
--@param type int {1(普通错误);2(战斗日志);3(缺少资源或资源命名不正确)}
--@param level int 堆栈起始级别
function FZutil.send_log(err,type,level)
    assert(not (type==3 and DEBUG>=2),err)
    if REMOTE_LOG==0 then return end
    local level_ =level or 2
    local dinfo = debug.getinfo( level_, "nSl") 
    if dinfo then
        local source=dinfo.source or ""
        local line=dinfo.currentline or 0
        local function_name=dinfo.name or ""
        local log=function_name .. "\n" ..err
        local type_=type or 1
        local server_id = (RoleData and RoleData.server_id) or 0
        local player_id = (RoleData and RoleData.player_info.player_id) or 0
        local info=require("info")
        local FzFileUtils=FzFileUtils or require("app.public.FzFileUtils")
        local oinfo=require(FzFileUtils.getOriginInfoPath())
        if type_==2 then 
            source="a.txt"
            log=err 
        end
        
        local httpStr=string.format("server_id=%s&player_id=%d&platform=%d&code_file=%s&code_line=%d&log=%s&type=%d",
            server_id, player_id,info.platform,source,line,log,type_)
            
        local xhr = cc.XMLHttpRequest:new() -- http请求  
        xhr.responseType = cc.XMLHTTPREQUEST_RESPONSE_STRING -- 响应类型  
        xhr:open("POST", oinfo.log_server) -- 打开链接  
        -- 状态改变时调用  
        local function onReadyStateChange() 
            local statusString = "Http Status Code:"..xhr.statusText 
            release_print(statusString)
            release_print(xhr.response)
        end  
        -- 注册脚本回调方法  
        xhr:registerScriptHandler(onReadyStateChange)  
        xhr:send(httpStr) -- 发送请求 
    end
end

---根据checkbox创建一个使用同一贴图的灰色的sprite
--@param checkbox ccui.Checkbox checkbox控件
--@return #cc.Sprite 灰色的Sprite
function FZutil.createCheckBoxGraySprite( checkbox )
    local frame=checkbox:getVirtualRenderer():getSpriteFrame()
    local graySp=filter.newFilteredSprite(frame,"GRAY")
    return graySp
end

---新类型按钮封装
---@param button buttonCover callback
function FZutil.onButtonTouch(btn, btnCover, callback)
    btnCover:setVisible(false)    
    btn:onTouch(function(event)
        if event.name == "began" then
            btnCover:setVisible(true)
        elseif event.name == "cancelled" or event.name == "ended" then
            btnCover:setVisible(false)
            if event.name == "ended" then
                callback()
            end
        end 
    end)
end

return FZutil